{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "#导包\n",
    "from surprise import Dataset\n",
    "from surprise import Reader\n",
    "from surprise import BaselineOnly, SlopeOne,KNNBasic, NormalPredictor\n",
    "from surprise import accuracy\n",
    "from surprise.model_selection import KFold\n",
    "import pandas as pd"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 读取数据与数据划分"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>userId</th>\n",
       "      <th>movieId</th>\n",
       "      <th>rating</th>\n",
       "      <th>timestamp</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1</td>\n",
       "      <td>2</td>\n",
       "      <td>3.5</td>\n",
       "      <td>1112486027</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1</td>\n",
       "      <td>29</td>\n",
       "      <td>3.5</td>\n",
       "      <td>1112484676</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>1</td>\n",
       "      <td>32</td>\n",
       "      <td>3.5</td>\n",
       "      <td>1112484819</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>1</td>\n",
       "      <td>47</td>\n",
       "      <td>3.5</td>\n",
       "      <td>1112484727</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>1</td>\n",
       "      <td>50</td>\n",
       "      <td>3.5</td>\n",
       "      <td>1112484580</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1048570</th>\n",
       "      <td>7120</td>\n",
       "      <td>168</td>\n",
       "      <td>5.0</td>\n",
       "      <td>1175543061</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1048571</th>\n",
       "      <td>7120</td>\n",
       "      <td>253</td>\n",
       "      <td>4.0</td>\n",
       "      <td>1175542225</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1048572</th>\n",
       "      <td>7120</td>\n",
       "      <td>260</td>\n",
       "      <td>5.0</td>\n",
       "      <td>1175542035</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1048573</th>\n",
       "      <td>7120</td>\n",
       "      <td>261</td>\n",
       "      <td>4.0</td>\n",
       "      <td>1175543376</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1048574</th>\n",
       "      <td>7120</td>\n",
       "      <td>266</td>\n",
       "      <td>3.5</td>\n",
       "      <td>1175542454</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>1048575 rows × 4 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "         userId  movieId  rating   timestamp\n",
       "0             1        2     3.5  1112486027\n",
       "1             1       29     3.5  1112484676\n",
       "2             1       32     3.5  1112484819\n",
       "3             1       47     3.5  1112484727\n",
       "4             1       50     3.5  1112484580\n",
       "...         ...      ...     ...         ...\n",
       "1048570    7120      168     5.0  1175543061\n",
       "1048571    7120      253     4.0  1175542225\n",
       "1048572    7120      260     5.0  1175542035\n",
       "1048573    7120      261     4.0  1175543376\n",
       "1048574    7120      266     3.5  1175542454\n",
       "\n",
       "[1048575 rows x 4 columns]"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data=pd.read_csv('ratings.csv')\n",
    "data#data数据集里面有 用户ID  电影的ID 评分 以及评分时间"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<surprise.reader.Reader object at 0x7fe753d33710> <class 'surprise.reader.Reader'>\n",
      "<surprise.dataset.DatasetAutoFolds object at 0x7fe753d33790> <class 'surprise.dataset.DatasetAutoFolds'>\n"
     ]
    }
   ],
   "source": [
    "#读取数据 用 surprise的格式\n",
    "reader = Reader(line_format='user item rating timestamp', sep=',', skip_lines=1)\n",
    "print(reader,type(reader))\n",
    "data = Dataset.load_from_file('ratings.csv', reader=reader)\n",
    "print(data,type(data))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<surprise.trainset.Trainset object at 0x7fe70c8c1e10> <class 'surprise.trainset.Trainset'>\n"
     ]
    }
   ],
   "source": [
    "train_set = data.build_full_trainset()\n",
    "print(train_set,type(train_set))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "SlopeOne算法\n",
    "SlopeOne算法基于user之间和item之间的评分差异来进行评分预测的。其大致分为三步：\n",
    "\n",
    "1、计算物品之间的评分差的均值，记为物品间的评分偏差(两物品同时被评分)；\n",
    "2、根据物品间的评分偏差和用户的历史评分，预测用户对未评分的物品的评分；\n",
    "3、将预测评分排序，取topN对应的物品推荐给用户"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "RMSE: 0.8664\n",
      "RMSE: 0.8691\n",
      "RMSE: 0.8678\n"
     ]
    }
   ],
   "source": [
    "# 使用SlopeOne算法\n",
    "algo2 = SlopeOne()\n",
    "# 定义K折交叉验证迭代器，K=3\n",
    "kf = KFold(n_splits=3)\n",
    "for trainset, testset in kf.split(data):\n",
    "    # 训练并预测\n",
    "    algo2.fit(trainset)\n",
    "    predictions = algo2.test(testset)\n",
    "    # 计算RMSE\n",
    "    accuracy.rmse(predictions, verbose=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "user: 136        item: 22         r_ui = 4.00   est = 3.99   {'was_impossible': False}\n"
     ]
    }
   ],
   "source": [
    "uid = str(136)\n",
    "iid = str(22)\n",
    "# 输出uid对iid的预测结果\n",
    "pred = algo2.predict(uid, iid, r_ui=4, verbose=True)#这里输出了用户136对电影22的评分"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
